#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include "uclient.h"
#include "usocket.h"
#include "umessage.h"

static Ucli_Info *g_cliinfo = NULL;

static int ucli_get_symbol()
{
    static int ucli_symbol = 0;

    return ucli_symbol++;
}

int ucli_recv(int symbol, void *buf, size_t len)
{
	Ucli_Info *p = NULL;
	
	HASH_FIND_INT(g_cliinfo, &symbol, p);
	
	if (!p)
		return -1;
	
	return usocket_recv(p->uc_fd, buf, len);
}

int ucli_send(int symbol, void *buf, size_t len)
{
	Ucli_Info *p = NULL;
	
	HASH_FIND_INT(g_cliinfo, &symbol, p);
	
	if (!p)
		return -1;
	
	return usocket_send(p->uc_fd, buf, len);	
}

static int ucli_parse_package_cb(int sockfd)
{
	int ret;
    Start_st startheader;
    unsigned char endcode;

    ret = usocket_recv(sockfd, &startheader, sizeof(Start_st));
	if (ret <= 0)
		goto bail1;

    if (USOCK_START_CODE != startheader.startcode)
        goto bail1;

    int package_len = sizeof(startheader) + startheader.ss_len + sizeof(endcode);
    
	unsigned char *package = (unsigned char *)malloc(package_len);
    char *pdata = (char *)(package + sizeof(startheader));

	ret = usocket_recv(sockfd, pdata, startheader.ss_len);
	if (ret <= 0)
		goto bail2;	

	ret = usocket_recv(sockfd, &endcode, sizeof(endcode));
	if (ret <= 0)
		goto bail2;

	if (USOCK_END_CODE != endcode)
		goto bail2;

    memcpy(package, &startheader, sizeof(startheader));
    package[sizeof(startheader) + startheader.ss_len] = endcode;
    
    pdata[startheader.ss_len] = '\0';
	umsg_parse_json_handle(startheader.ss_type, pdata);

    if (package)
	{
		free(package);
        package = NULL;
	}

    return package_len;
	
bail2:
	if (package)
	{
		free(package);
        package = NULL;
	}
bail1:
	return -1;		
}

static void *ucli_handle(void *args)
{
    fd_set readfds;
    struct timeval tv;
    int ret;
    int sockfd;

    if (!args)
        return NULL;

    Ucli_Info *pout = (Ucli_Info *)args;

    sockfd = usocket_connect(pout->path);
    pout->uc_fd = sockfd;

    while (1)
    {
        tv.tv_sec = 2;
        tv.tv_usec = 0;
        FD_ZERO(&readfds);

        if (-1 != sockfd)
        {
            FD_SET(sockfd, &readfds);
        }
        else
        {
            sockfd = usocket_connect(pout->path);
            if (-1 != sockfd)
            {
                pout->uc_fd = sockfd;
            }
            else
            {
                sleep(2);
                continue;
            }
        }

        ret = select(sockfd + 1, &readfds, NULL, NULL, &tv);

        if (0 == ret)
        {
            continue;
        }
        else if (-1 == ret)
        {
            fprintf(stderr, "select error:%s\n", strerror(errno));
            break;
        }
        else
        {
            if (FD_ISSET(sockfd, &readfds))
            {
                ret = pout->uc_cb(sockfd);
                if (ret <= 0)
                {
                    close(sockfd);
                    sockfd = -1;
                }
            }
        }
    }

    return NULL ;
}

void ucli_destroy(int symbol)
{
	Ucli_Info *p = NULL;
	
	HASH_FIND_INT(g_cliinfo, &symbol, p);
	
	if (!p)
		return;
	
	HASH_DEL(g_cliinfo, p);
	free(p->path);
	if (-1 != p->uc_fd)
		close(p->uc_fd);
	free(p);
    p = NULL;
}

int ucli_create(const char *path, int dev, cli_parse_cb cb)
{
    if (!path || !*path)
        return -1;
    
    Ucli_Info *pout = (Ucli_Info *)malloc(sizeof(Ucli_Info));
    memset(pout, 0, sizeof(Ucli_Info));
    pout->path = strdup(path);
    pout->uc_dev = dev;
    pout->uc_symbol = ucli_get_symbol();
    if (cb)
        pout->uc_cb = cb;
    else
        pout->uc_cb = ucli_parse_package_cb;
    HASH_ADD_INT(g_cliinfo, uc_symbol, pout);
    create_thread(ucli_handle, pout, PTHREAD_STACK_MIN);
    return pout->uc_symbol;
}
/*
int main()
{
	int symbol = ucli_create("lvswitches");
	
	//ucli_send(symbol, "12345");
	
	
	
}
*/
